﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using Reflector.CodeModel;

namespace CallGraphExtractor
{
    [DebuggerDisplay("{MemberReference.Name} in {Module} module")]
    public struct ExtendedMemberReference
    {
        public ExtendedMemberReference(IModule module, IMemberReference memberReference)
            : this()
        {
            this.Module = module;
            this.MemberReference = memberReference;
        }

        public IModule Module { get; private set; }
        public IMemberReference MemberReference { get; private set; }
    }

    [DebuggerDisplay("{Type} nested in {OuterType} in {Module} module")]
    public struct ExtendedType
    {
        public ExtendedType(IModule module, IType type, IType outerType = null)
            : this()
        {
            if (module == null)
                throw new ArgumentNullException("module");
            if (type == null)
                throw new ArgumentNullException("type");
            this.Module = module;
            this.Type = type;
            this.OuterType = outerType;
        }

        public IModule Module { get; private set; }
        public IType Type { get; private set; }
        public IType OuterType { get; private set; }

        #region Members

        public override bool Equals(object obj)
        {
            ExtendedType et;
            try
            {
                et = (ExtendedType)obj;
            }
            catch (InvalidCastException)
            {
                return false;
            }
            return this.Module == et.Module && this.Type == et.Type
                || this.Module.Equals(et.Module) && this.Type.Equals(et.Type);
        }

        public override int GetHashCode()
        {
            int modulHC = this.Module == null ? 1 : this.Module.GetHashCode();
            int typeHC = this.Type == null ? 1 : this.Type.GetHashCode();
            return modulHC ^ typeHC;
        }

        #endregion Members
    }

    public struct CallGraphEdge
    {
        public CallGraphEdge(ExtendedMemberReference emr, CallTypes callType)
            : this()
        {
            this.ExtendedMemberReference = emr;
            this.CallType = callType;
        }

        public ExtendedMemberReference ExtendedMemberReference { get; private set; }
        public CallTypes CallType { get; private set; }
    }

    public class CallGraphEdgeCollection
    {
        public ExtendedMemberReference Caller { get; private set; }
        public ReadOnlyCollection<CallGraphEdge> Called { get; private set; }

        public CallGraphEdgeCollection(ExtendedMemberReference caller,
            IList<CallGraphEdge> called)
        {
            this.Caller = caller;
            this.Called = new ReadOnlyCollection<CallGraphEdge>(called);
        }

        //public void SetCalled(IList<IMemberReference> called)
        //{
        //    this.Called = new ReadOnlyCollection<IMemberReference>(called);
        //}
    }
}
